//
//  ConstraintsHelper.swift
//  BasicTools
//
//  Created by Ting Han on 2022/3/11.
//

import Foundation
import UIKit

precedencegroup ConstraintPrecedence {
    associativity: left
    higherThan: AssignmentPrecedence
}

infix operator >>>-: ConstraintPrecedence


struct ConstraintInfo {
    var attribute: NSLayoutConstraint.Attribute = .left
    var secondAttribute: NSLayoutConstraint.Attribute = .notAnAttribute
    var relation: NSLayoutConstraint.Relation = .equal
    var multiplier: CGFloat = 1
    var constant: CGFloat = 0
    var identifier: String?
}

/*
 view1.attr1 = view2.attr2 * multiplier + constant
 */

@discardableResult
func >>>- <T: UIView> (lhs: T, rhs: (inout ConstraintInfo) -> Void) -> NSLayoutConstraint {
    var info = ConstraintInfo()
    rhs(&info)
    let constraint = NSLayoutConstraint(
        item: lhs,
        attribute: info.attribute,
        relatedBy: info.relation,
        toItem: nil,
        attribute: info.attribute,
        multiplier: info.multiplier,
        constant: info.constant)
    constraint.identifier = info.identifier
    lhs.addConstraint(constraint)
    
    return constraint
}

@discardableResult
func >>>- <T: UIView> (lhs: (T, T), rhs: (inout ConstraintInfo) -> Void) -> NSLayoutConstraint {
    var info = ConstraintInfo()
    rhs(&info)
    info.secondAttribute = info.secondAttribute == .notAnAttribute ? info.attribute : info.secondAttribute
    
    let constraint = NSLayoutConstraint(
        item: lhs.1,
        attribute: info.secondAttribute,
        relatedBy: info.relation,
        toItem: lhs.0,
        attribute: info.attribute,
        multiplier: info.multiplier,
        constant: info.constant)
    constraint.identifier = info.identifier
    lhs.0.addConstraint(constraint)
    
    return constraint
}

@discardableResult
func >>>- <T: UIView> (lhs: (T, T, T), rhs: (inout ConstraintInfo) -> Void) -> NSLayoutConstraint {
    var info = ConstraintInfo()
    rhs(&info)
    info.secondAttribute = info.secondAttribute == .notAnAttribute ? info.attribute : info.secondAttribute
    
    let constraint = NSLayoutConstraint(
        item: lhs.2,
        attribute: info.secondAttribute,
        relatedBy: info.relation,
        toItem: lhs.1,
        attribute: info.attribute,
        multiplier: info.multiplier,
        constant: info.constant)
    constraint.identifier = info.identifier
    lhs.0.addConstraint(constraint)
    
    return constraint
}

/*
 1.约束不依赖于其他控件（添加的约束和其他控件没有关系），会添加到自己身上: >>>-(T)
 2.如果是父子关系，设置子控件的约束，约束添加到父控件上: >>>-(T,T)
 3.如果是兄弟关系，设置两兄弟的约束，约束添加到第一个共同的父控件上: >>>-(T,T,T)
 */

/*
 example:
 
 red >>>- {
     $0.attribute = .width
     $0.constant = 250
 }
 red >>>- {
     $0.attribute = .height
     $0.constant = 250
 }
 
 (view, red) >>>- {
     $0.attribute = .leading
     $0.constant = 100
 }
 
 (view, red) >>>- {
     $0.attribute = .top
     $0.constant = 150
 }
 
 (view, red, green) >>>- {
     $0.attribute = .width
     $0.multiplier = 0.5
 }
 
 green >>>- {
     $0.attribute = .height
     $0.constant = 150
 }
 
 (view, red, green) >>>- {
     $0.attribute = .bottom
     $0.secondAttribute = .top
     $0.constant = 20
 }
 
 (view, red, green) >>>- {
     $0.attribute = .centerX
     $0.constant = 10
 }
 */
